home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / drivers / char / atari_serial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  24.9 KB  |  984 lines

  1.  
  2. /*
  3.  * drivers/char/atari_serial.c: Common source file for all Atari serial ports
  4.  *
  5.  * Copyright 1994 Roman Hodek
  6.  *   EMail: rnhodek@cip.informatik.uni-erlangen.de (Internet)
  7.  *      or: Roman_Hodek@n.maus.de (MausNet, NO mail > 16 KB!)
  8.  *
  9.  * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o
  10.  * 
  11.  * This file is subject to the terms and conditions of the GNU General Public
  12.  * License.  See the file README.legal in the main directory of this archive
  13.  * for more details.
  14.  *
  15.  */
  16.  
  17. /*
  18.  * Notes and Design Goals:
  19.  * -----------------------
  20.  * The PC serial drivers can rely on the fact that all the serial
  21.  * hardware is very similar to program for all ports. Unfortunately,
  22.  * this is not true for the Atari. Here it is nearly the other way
  23.  * round: All ports need different treatment for the low-level stuff.
  24.  *
  25.  * For this reason, I split the serial driver code into a
  26.  * port-independent part (atari_serial.c) and port-specific parts
  27.  * (atari_*.c). The first manages all what can be done without
  28.  * accessing the hardware directly, i.e. interfacing with the
  29.  * high-level tty drivers, wait queues, managing the existing ports
  30.  * and the like. The latter do the actual hardware programming and are
  31.  * accessed by the hardware-independant part by a "switch" structure,
  32.  * that contains pointers to functions for specific tasks. See the
  33.  * comment before the definition of the SERIALSWITCH structure in
  34.  * atari_serial.h for more details.
  35.  *
  36.  * Despite its name, the port-independant code should be usable by
  37.  * other machines than Atari, too, if there are similar circumstances
  38.  * with different serial port hardware. Feel free to use it, but
  39.  * please inform me if you have to do changes to it. I'll try to keep
  40.  * it really device-independant. 
  41.  *
  42.  */
  43.  
  44.  
  45. #include <linux/types.h>
  46. #include <linux/sched.h>
  47. #include <linux/timer.h>
  48. #include <linux/errno.h>
  49. #include <linux/string.h>
  50. #include <linux/bootinfo.h>
  51. #include <linux/tty.h>
  52. #include <linux/termios.h>
  53. #include <linux/major.h>
  54. #include <linux/fcntl.h>
  55.  
  56. #include <asm/bitops.h>
  57. #include <asm/segment.h>
  58.  
  59. #include "atari_serial.h"
  60. #include "atari_SCC.h"
  61. #include "atari_MFPser.h"
  62.  
  63.  
  64.  
  65. struct async_struct rs_table[ NR_PORTS ];
  66. char rs_event[ (NR_PORTS + 7) / 8 ];
  67.  
  68.  
  69.  
  70. /***************************** Prototypes *****************************/
  71.  
  72. static inline void handle_rs_break( struct async_struct *info );
  73. static void do_softint( void *unused );
  74. static int startup( struct async_struct * info, int get_irq );
  75. static void shutdown( struct async_struct * info, int do_free_irq );
  76. static int get_serial_info( struct async_struct * info, struct
  77.                             serial_struct * retinfo );
  78. static int set_serial_info( struct async_struct * info, struct
  79.                             serial_struct * new_info );
  80. static int get_modem_info( struct async_struct * info, unsigned int *value
  81.                            );
  82. static int set_modem_info( struct async_struct * info, unsigned int cmd,
  83.                            unsigned int *value );
  84. static void send_break( struct async_struct * info, int duration );
  85. static int rs_ioctl( struct tty_struct *tty, struct file * file, unsigned
  86.                      int cmd, unsigned long arg );
  87. static void rs_set_termios( struct tty_struct *tty, struct termios
  88.                             *old_termios );
  89. static void rs_close( struct tty_struct *tty, struct file * filp );
  90. static int block_til_ready( struct tty_struct *tty, struct file * filp,
  91.                             struct async_struct *info );
  92.  
  93. /************************* End of Prototypes **************************/
  94.  
  95.  
  96.  
  97. /*
  98.  * ------------------------------------------------------------
  99.  * rs_stop() and rs_start()
  100.  *
  101.  * This routines are called before setting or resetting tty->stopped.
  102.  * They enable or disable transmitter interrupts, as necessary.
  103.  * ------------------------------------------------------------ */
  104.  
  105. void rs_stop( struct tty_struct *tty )
  106.  
  107. {
  108.     struct async_struct *info;
  109.     
  110.     info = rs_table + DEV_TO_SL(tty->line);
  111.  
  112.     if (info->flags & ASYNC_CLOSING) {
  113.         tty->stopped = 0;
  114.         tty->hw_stopped = 0;
  115.         return;
  116.     }
  117.  
  118.     if (info->sw->enab_tx_int)
  119.         info->sw->enab_tx_int( info, 0 );
  120. }
  121.  
  122. void rs_start( struct tty_struct *tty )
  123.  
  124. {
  125.     struct async_struct *info;
  126.  
  127.     info = rs_table + DEV_TO_SL(tty->line);
  128.     
  129.     if (info->sw->enab_tx_int) {
  130.         info->sw->enab_tx_int( info, 1 );
  131.     }
  132. }
  133.  
  134.  
  135. /*
  136.  * This routine is called when we receive a break on a serial line.
  137.  * It is executed out of the software interrupt routine.
  138.  */
  139.  
  140. static inline void handle_rs_break( struct async_struct *info )
  141.  
  142. {
  143.     if (info->flags & ASYNC_SAK)
  144.         do_SAK(info->tty);
  145.         
  146.     if (!I_IGNBRK(info->tty) && I_BRKINT(info->tty)) {
  147.         flush_input(info->tty);
  148.         flush_output(info->tty);
  149.         if (info->tty->pgrp > 0)
  150.             kill_pg(info->tty->pgrp, SIGINT, 1 );
  151.     }
  152. }
  153.  
  154. /*
  155.  * This routine is used to handle the "bottom half" processing for the
  156.  * serial driver, known also the "software interrupt" processing.
  157.  * This processing is done at the kernel interrupt level, after the
  158.  * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
  159.  * is where time-consuming activities which can not be done in the
  160.  * interrupt driver proper are done; the interrupt driver schedules
  161.  * them using rs_sched_event(), and they get done here.
  162.  */
  163. static void do_softint( void *unused )
  164.  
  165. {
  166.     int            i;
  167.     struct async_struct    *info;
  168.     
  169.     for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
  170.         if (clear_bit(i, rs_event)) {
  171.             if (!info->tty)    
  172.                 continue;
  173.             if (clear_bit(RS_EVENT_READ_PROCESS, &info->event)) {
  174.                 TTY_READ_FLUSH(info->tty);
  175.             }
  176.             if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
  177.                 wake_up_interruptible(&info->tty->write_q.proc_list);
  178.             }
  179.             if (clear_bit(RS_EVENT_HANGUP, &info->event)) {
  180.                 tty_hangup(info->tty);
  181.                 wake_up_interruptible(&info->open_wait);
  182.                 info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
  183.             }
  184.             if (clear_bit(RS_EVENT_BREAK, &info->event))
  185.                 handle_rs_break(info);
  186.             if (clear_bit(RS_EVENT_OPEN_WAKEUP, &info->event)) {
  187.                 wake_up_interruptible(&info->open_wait);
  188.             }
  189.         }
  190.     }
  191. }
  192.  
  193. static int startup( struct async_struct * info, int get_irq )
  194.  
  195. {
  196.     unsigned long flags;
  197.  
  198.     if (info->flags & ASYNC_INITIALIZED)
  199.         return 0;
  200.  
  201.     if (!info->base || !info->type) {
  202.         if (info->tty)
  203.             set_bit(TTY_IO_ERROR, &info->tty->flags);
  204.         return 0;
  205.     }
  206.  
  207.     save_flags(flags); cli();
  208.  
  209. #ifdef SERIAL_DEBUG_OPEN
  210.     printk("starting up ttys%d (irq %d)...", info->line, info->irq);
  211. #endif
  212.  
  213.     info->sw->init( info );
  214.  
  215.     if (info->tty)
  216.         clear_bit(TTY_IO_ERROR, &info->tty->flags);
  217.  
  218.     /*
  219.      * Set the speed and other port parameters.
  220.      */
  221.     info->sw->change_speed( info );
  222.  
  223.     info->flags |= ASYNC_INITIALIZED;
  224.     restore_flags(flags);
  225.     return 0;
  226. }
  227.  
  228. /*
  229.  * This routine will shutdown a serial port; interrupts are disabled, and
  230.  * DTR is dropped if the hangup on close termio flag is on.
  231.  */
  232.  
  233. static void shutdown( struct async_struct * info, int do_free_irq )
  234.  
  235. {
  236.     unsigned long flags;
  237.  
  238.     if (!(info->flags & ASYNC_INITIALIZED))
  239.         return;
  240.  
  241. #ifdef SERIAL_DEBUG_OPEN
  242.     printk("Shutting down serial port %d (irq %d)....", info->line,
  243.            info->irq);
  244. #endif
  245.     
  246.     save_flags(flags); cli(); /* Disable interrupts */
  247.     
  248.     info->sw->deinit( info, info->tty &&
  249.                             !(info->tty->termios->c_cflag & HUPCL) );
  250.     
  251.     if (info->tty)
  252.         set_bit(TTY_IO_ERROR, &info->tty->flags);
  253.     
  254.     info->flags &= ~ASYNC_INITIALIZED;
  255.     restore_flags(flags);
  256. }
  257.  
  258.  
  259. /*
  260.  * ------------------------------------------------------------
  261.  * rs_write() and friends
  262.  * ------------------------------------------------------------
  263.  */
  264.  
  265. /*
  266.  * This routine gets called when tty_write has put something into
  267.  * the write_queue.  
  268.  */
  269.  
  270. void rs_write( struct tty_struct * tty )
  271.  
  272. {    struct async_struct *info;
  273.  
  274.     if (!tty || tty->stopped || tty->hw_stopped)
  275.         return;
  276.     info = rs_table + DEV_TO_SL(tty->line);
  277.     
  278.     if (!info || !info->tty || !(info->flags & ASYNC_INITIALIZED))
  279.         return;
  280.  
  281.     cli();
  282.     info->sw->restart( info, rs_get_char_from_queue( info ) );
  283.     if (info->sw->enab_tx_int)
  284.         info->sw->enab_tx_int( info, 1 );
  285.     sti();
  286. }
  287.  
  288.  
  289. /*
  290.  * ------------------------------------------------------------
  291.  * rs_throttle()
  292.  * 
  293.  * This routine is called by the upper-layer tty layer to signal that
  294.  * incoming characters should be throttled (and that the throttle
  295.  * should be released).
  296.  * ------------------------------------------------------------
  297.  */
  298.  
  299. void rs_throttle( struct tty_struct * tty, int status )
  300.  
  301. {
  302.     struct async_struct *info;
  303.     unsigned long flags;
  304.  
  305.     save_flags(flags); cli();
  306. #if SERIAL_DEBUG_THROTTLE
  307.     printk("throttle tty%d: %d (%d, %d)....\n", DEV_TO_SL(tty->line),
  308.            status, LEFT(&tty->read_q), LEFT(&tty->secondary));
  309. #endif
  310.  
  311.     switch( status ) {
  312.  
  313.       case TTY_THROTTLE_RQ_FULL:
  314.         info = rs_table + DEV_TO_SL(tty->line);
  315.         if (I_IXOFF(tty))
  316.             info->x_char = STOP_CHAR(tty);
  317.         else if (C_CRTSCTS(tty))
  318.             info->sw->throttle( info, status );
  319.         break;
  320.  
  321.       case TTY_THROTTLE_RQ_AVAIL:
  322.         info = rs_table + DEV_TO_SL(tty->line);
  323.         if (I_IXOFF(tty)) {
  324.             if (info->x_char)
  325.                 info->x_char = 0;
  326.             else
  327.                 info->x_char = START_CHAR(tty);
  328.         } else if (C_CRTSCTS(tty))
  329.             info->sw->throttle( info, status );
  330.         break;
  331.     }
  332.  
  333.     restore_flags(flags);
  334. }
  335.  
  336. /*
  337.  * ------------------------------------------------------------
  338.  * rs_ioctl() and friends
  339.  * ------------------------------------------------------------
  340.  */
  341.  
  342. static int get_serial_info( struct async_struct * info,
  343.                             struct serial_struct * retinfo )
  344.  
  345. {
  346.     struct serial_struct tmp;
  347.   
  348.     if (!retinfo)
  349.         return -EFAULT;
  350.  
  351.     /* Set port-independant data */
  352.     memset(&tmp, 0, sizeof(tmp));
  353.     tmp.type        = info->type;
  354.     tmp.line        = info->line;
  355.     tmp.port        = 0;    /* meaningless for non-Intel */
  356.     tmp.irq         = 0;    /* meaningless for Atari */
  357.     tmp.flags       = info->flags;
  358.     tmp.close_delay = info->close_delay;
  359.     tmp.hub6        = 0;    /* meaningless for Atari */
  360.  
  361.     /* At least baud_base and costum_divisor set by port-specific
  362.      * function
  363.      */
  364.     info->sw->get_serial_info( info, &tmp );
  365.     
  366.     memcpy_tofs( retinfo, &tmp, sizeof(*retinfo) );
  367.     return 0;
  368. }
  369.  
  370.  
  371. static int set_serial_info( struct async_struct * info,
  372.                             struct serial_struct * new_info )
  373.  
  374. {
  375.     struct serial_struct    new_serial;
  376.     struct async_struct     old_info;
  377.     
  378.     if (!new_info) return( -EFAULT );
  379.     memcpy_fromfs( &new_serial, new_info, sizeof(new_serial) );
  380.     old_info = *info;
  381.  
  382.     /* The fields type, line, port, irq, xmit_fifo_size, baud_base and
  383.      * hub6 of new_info are silently ignored for the Atari, since they
  384.      * are meaningless or cannot be changed, resp. Is this right or
  385.      * should an error be returned?
  386.      */
  387.  
  388.     /* If a new custom divisor is to be set, let it check by the
  389.      * hardware specific code first!
  390.      */
  391.     if (new_serial.custom_divisor != info->custom_divisor) {
  392.         if (info->sw->check_custom_divisor( info, new_serial.custom_divisor ))
  393.             return( -EINVAL );
  394.     }
  395.     
  396.     if (!suser()) {
  397.         if ((new_serial.close_delay != info->close_delay) ||
  398.             ((new_serial.flags & ~ASYNC_USR_MASK) !=
  399.              (info->flags & ~ASYNC_USR_MASK))) return( -EPERM );
  400.  
  401.         info->flags = ((info->flags & ~ASYNC_USR_MASK) |
  402.                        (new_serial.flags & ASYNC_USR_MASK));
  403.         info->custom_divisor = new_serial.custom_divisor;
  404.         goto check_and_exit;
  405.     }
  406.  
  407.     /*
  408.      * OK, past this point, all the error checking has been done.
  409.      * At this point, we start making changes.....
  410.      */
  411.  
  412.     info->flags = ((info->flags & ~ASYNC_FLAGS) |
  413.                    (new_serial.flags & ASYNC_FLAGS));
  414.     info->custom_divisor = new_serial.custom_divisor;
  415.     info->close_delay = new_serial.close_delay;
  416.  
  417. check_and_exit:
  418.     if (info->flags & ASYNC_INITIALIZED) {
  419.  
  420.         if (((old_info.flags & ASYNC_SPD_MASK) !=
  421.              (info->flags & ASYNC_SPD_MASK)) ||
  422.             (old_info.custom_divisor != info->custom_divisor))
  423.             info->sw->change_speed( info ); 
  424.     }
  425.     else
  426.         (void)startup( info, 0 );
  427.  
  428.     return 0;
  429. }
  430.  
  431. static int get_modem_info( struct async_struct * info,
  432.                            unsigned int *value )
  433.  
  434. {
  435.     unsigned int result;
  436.  
  437.     result = info->sw->get_modem_info( info );
  438.     put_fs_long( result, (unsigned long *) value );
  439.  
  440.     return 0;
  441. }
  442.  
  443.  
  444. static int set_modem_info( struct async_struct * info, unsigned int cmd,
  445.                            unsigned int *value )
  446.  
  447. {    unsigned    arg = get_fs_long((unsigned long *) value);
  448.     int            new_dtr = -1, new_rts = -1;
  449.  
  450.     switch( cmd ) {
  451.  
  452.       case TIOCMBIS:
  453.         if (arg & TIOCM_DTR) new_dtr = 1;
  454.         if (arg & TIOCM_RTS) new_rts = 1;
  455.         break;
  456.  
  457.       case TIOCMBIC:
  458.         if (arg & TIOCM_DTR) new_dtr = 0;
  459.         if (arg & TIOCM_RTS) new_rts = 0;
  460.         break;
  461.  
  462.       case TIOCMSET:
  463.         new_dtr = !!(arg & TIOCM_DTR);
  464.         new_rts = !!(arg & TIOCM_RTS);
  465.         break;
  466.  
  467.       default:
  468.         return( -EINVAL );
  469.     }
  470.     
  471.     return( info->sw->set_modem_info( info, new_dtr, new_rts ) );
  472. }
  473.  
  474.  
  475. /*
  476.  * This routine sends a break out the serial port.
  477.  */
  478.  
  479. static void send_break(    struct async_struct * info, int duration )
  480.  
  481. {
  482.     if (!info->base) return;
  483.     
  484.     current->state = TASK_INTERRUPTIBLE;
  485.     current->timeout = jiffies + duration;
  486.     cli();
  487.     info->sw->set_break( info, 1 );
  488.     schedule();
  489.     info->sw->set_break( info, 0 );
  490.     sti();
  491. }
  492.  
  493. static int rs_ioctl( struct tty_struct *tty, struct file * file,
  494.                      unsigned int cmd, unsigned long arg )
  495.  
  496. {
  497.     int error, line;
  498.     struct async_struct * info;
  499.  
  500.     line = DEV_TO_SL(tty->line);
  501.     if (line < 0 || line >= NR_PORTS)
  502.         return -ENODEV;
  503.     info = rs_table + line;
  504.     if (!info->base) return( -ENODEV );
  505.     
  506.     switch( cmd ) {
  507.       case TCSBRK:    /* SVID version: non-zero arg --> no break */
  508.         if (!arg)
  509.             send_break(info, HZ/4);    /* 1/4 second */
  510.         return 0;
  511.       case TCSBRKP:    /* support for POSIX tcsendbreak() */
  512.         send_break(info, arg ? arg*(HZ/10) : HZ/4);
  513.         return 0;
  514.       case TIOCGSOFTCAR:
  515.         error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
  516.         if (error)
  517.             return error;
  518.         put_fs_long(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
  519.         return 0;
  520.       case TIOCSSOFTCAR:
  521.         arg = get_fs_long((unsigned long *) arg);
  522.         tty->termios->c_cflag =
  523.             ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
  524.         return 0;
  525.       case TIOCMGET:
  526.         error = verify_area(VERIFY_WRITE, (void *) arg,
  527.                             sizeof(unsigned int));
  528.         if (error)
  529.             return error;
  530.         return get_modem_info(info, (unsigned int *) arg);
  531.       case TIOCMBIS:
  532.       case TIOCMBIC:
  533.       case TIOCMSET:
  534.         return set_modem_info(info, cmd, (unsigned int *) arg);
  535.       case TIOCGSERIAL:
  536.         error = verify_area(VERIFY_WRITE, (void *) arg,
  537.                             sizeof(struct serial_struct));
  538.         if (error)
  539.             return error;
  540.         return get_serial_info(info, (struct serial_struct *) arg);
  541.       case TIOCSSERIAL:
  542.         return set_serial_info(info, (struct serial_struct *) arg);
  543.       case TIOCSERCONFIG:
  544.         /* return do_autoconfig(info); */
  545.         return( 0 );
  546.         
  547.       default:
  548.         if (info->sw->ioctl)
  549.             return( info->sw->ioctl( tty, file, info, cmd, arg ) );
  550.         else
  551.             return( -EINVAL );
  552.     }
  553.     return 0;
  554. }
  555.  
  556.  
  557. static void rs_set_termios( struct tty_struct *tty,
  558.                             struct termios *old_termios )
  559.  
  560. {
  561.     struct async_struct *info;
  562.  
  563.     if (tty->termios->c_cflag == old_termios->c_cflag)
  564.         return;
  565.  
  566.     info = &rs_table[DEV_TO_SL(tty->line)];
  567.  
  568.     info->sw->change_speed( info );
  569.     
  570.     if ((old_termios->c_cflag & CRTSCTS) &&
  571.         !(tty->termios->c_cflag & CRTSCTS)) {
  572.         tty->hw_stopped = 0;
  573.         rs_write(tty);
  574.     }
  575.  
  576.     if (!(old_termios->c_cflag & CLOCAL) &&
  577.         (tty->termios->c_cflag & CLOCAL))
  578.         wake_up_interruptible(&info->open_wait);
  579. }
  580.  
  581.  
  582. /*
  583.  * ------------------------------------------------------------
  584.  * rs_close()
  585.  * 
  586.  * This routine is called when the serial port gets closed.  First, we
  587.  * wait for the last remaining data to be sent.  Then, we unlink its
  588.  * async structure from the interrupt chain if necessary, and we free
  589.  * that IRQ if nothing is left in the chain.
  590.  * ------------------------------------------------------------
  591.  */
  592.  
  593. static void rs_close( struct tty_struct *tty, struct file * filp )
  594.  
  595. {
  596.     struct async_struct * info;
  597.     int line;
  598.  
  599.     if (tty_hung_up_p(filp)) return;
  600.     
  601.     line = DEV_TO_SL(tty->line);
  602.     if ((line < 0) || (line >= NR_PORTS)) return;
  603.     info = rs_table + line;
  604.     if (!info->base) return;
  605.     
  606. #ifdef SERIAL_DEBUG_OPEN
  607.     printk("rs_close ttys%d, count = %d\n", info->line, info->count);
  608. #endif
  609.  
  610.     if ((tty->count == 1) && (info->count != 1)) {
  611.         /*
  612.          * Uh, oh.  tty->count is 1, which means that the tty
  613.          * structure will be freed.  Info->count should always
  614.          * be one in these conditions.  If it's greater than
  615.          * one, we've got real problems, since it means the
  616.          * serial port won't be shutdown.
  617.          */
  618.         printk("rs_close: bad serial port count; tty->count is 1, "
  619.                "info->count is %d\n", info->count);
  620.         info->count = 1;
  621.     }
  622.     if (--info->count < 0) {
  623.         printk("rs_close: bad serial port count for ttys%d: %d\n",
  624.                info->line, info->count);
  625.         info->count = 0;
  626.     }
  627.     if (info->count)
  628.         return;
  629.     info->flags |= ASYNC_CLOSING;
  630.     /*
  631.      * Save the termios structure, since this port may have
  632.      * separate termios for callout and dialin.
  633.      */
  634.     if (info->flags & ASYNC_NORMAL_ACTIVE)
  635.         info->normal_termios = *tty->termios;
  636.     if (info->flags & ASYNC_CALLOUT_ACTIVE)
  637.         info->callout_termios = *tty->termios;
  638.     tty->stopped = 0;        /* Force flush to succeed */
  639.     tty->hw_stopped = 0;
  640.     if (info->flags & ASYNC_INITIALIZED) {
  641.         rs_start(tty);
  642.         wait_until_sent(tty, 6000); /* 60 seconds timeout */
  643.     } else
  644.         flush_output(tty);
  645.     flush_input(tty);
  646.  
  647.     shutdown(info, 1);
  648.     clear_bit(line, rs_event);
  649.     info->event = 0;
  650.     info->tty = 0;
  651.     if (info->blocked_open) {
  652.         if (info->close_delay) {
  653.             tty->count++; /* avoid race condition */
  654.             current->state = TASK_INTERRUPTIBLE;
  655.             current->timeout = jiffies + info->close_delay;
  656.             schedule();
  657.             tty->count--;
  658.         }
  659.         wake_up_interruptible(&info->open_wait);
  660.     }
  661.     info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
  662.     wake_up_interruptible(&info->close_wait);
  663. }
  664.  
  665.  
  666. /*
  667.  * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
  668.  */
  669.  
  670. void rs_hangup( struct tty_struct *tty )
  671.  
  672. {
  673.     struct async_struct * info;
  674.     int line;
  675.  
  676.     line = DEV_TO_SL(tty->line);
  677.     if ((line < 0) || (line >= NR_PORTS)) return;
  678.     info = rs_table + line;
  679.     if (!info->base) return;
  680.     
  681.     shutdown(info, 1);
  682.     clear_bit(line, rs_event);
  683.     info->event = 0;
  684.     info->count = 0;
  685.     info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
  686.     info->tty = 0;
  687.     wake_up_interruptible(&info->open_wait);
  688. }
  689.  
  690.  
  691. /*
  692.  * ------------------------------------------------------------
  693.  * rs_open() and friends
  694.  * ------------------------------------------------------------
  695.  */
  696.  
  697. static int block_til_ready( struct tty_struct *tty, struct file * filp,
  698.                             struct async_struct *info )
  699.  
  700. {
  701.     struct wait_queue wait = { current, NULL };
  702.     int        retval;
  703.     int        do_clocal = C_CLOCAL(tty);
  704.  
  705.     /*
  706.      * If the device is in the middle of being closed, then block
  707.      * until it's done, and then try again.
  708.      */
  709.     if (info->flags & ASYNC_CLOSING) {
  710.         interruptible_sleep_on(&info->close_wait);
  711. #ifdef SERIAL_DO_RESTART
  712.         if (info->flags & ASYNC_HUP_NOTIFY)
  713.             return -EAGAIN;
  714.         else
  715.             return -ERESTARTSYS;
  716. #else
  717.         return -EAGAIN;
  718. #endif
  719.     }
  720.  
  721.     /*
  722.      * If this is a callout device, then just make sure the normal
  723.      * device isn't being used.
  724.      */
  725.     if (MAJOR(filp->f_rdev) == TTYAUX_MAJOR) {
  726.         if (info->flags & ASYNC_NORMAL_ACTIVE)
  727.             return -EBUSY;
  728.         if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  729.             (info->flags & ASYNC_SESSION_LOCKOUT) &&
  730.             (info->session != current->session))
  731.             return -EBUSY;
  732.         if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
  733.             (info->flags & ASYNC_PGRP_LOCKOUT) &&
  734.             (info->pgrp != current->pgrp))
  735.             return -EBUSY;
  736.         info->flags |= ASYNC_CALLOUT_ACTIVE;
  737.         return 0;
  738.     }
  739.     
  740.     /*
  741.      * If non-blocking mode is set, then make the check up front
  742.      * and then exit.
  743.      */
  744.     if (filp->f_flags & O_NONBLOCK) {
  745.         if (info->flags & ASYNC_CALLOUT_ACTIVE)
  746.             return -EBUSY;
  747.         info->flags |= ASYNC_NORMAL_ACTIVE;
  748.         return 0;
  749.     }
  750.  
  751.     /*
  752.      * Block waiting for the carrier detect and the line to become
  753.      * free (i.e., not in use by the callout).  While we are in
  754.      * this loop, info->count is dropped by one, so that
  755.      * rs_close() knows when to free things.  We restore it upon
  756.      * exit, either normal or abnormal.
  757.      */
  758.     retval = 0;
  759.     add_wait_queue(&info->open_wait, &wait);
  760. #ifdef SERIAL_DEBUG_OPEN
  761.     printk("block_til_ready before block: ttys%d, count = %d\n",
  762.            info->line, info->count);
  763. #endif
  764.     info->count--;
  765.     info->blocked_open++;
  766.     while (1) {
  767.         cli();
  768.         if (!(info->flags & ASYNC_CALLOUT_ACTIVE))
  769.             info->sw->set_modem_info( info, 1, 1 );
  770.         sti();
  771.         current->state = TASK_INTERRUPTIBLE;
  772.         if (tty_hung_up_p(filp) ||
  773.             !(info->flags & ASYNC_INITIALIZED)) {
  774. #ifdef SERIAL_DO_RESTART
  775.             if (info->flags & ASYNC_HUP_NOTIFY)
  776.                 retval = -EAGAIN;
  777.             else
  778.                 retval = -ERESTARTSYS;
  779. #else
  780.             retval = -EAGAIN;
  781. #endif
  782.             break;
  783.         }
  784.         if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
  785.             !(info->flags & ASYNC_CLOSING) &&
  786.             (do_clocal || (info->sw->get_modem_info( info ) & TIOCM_CAR)))
  787.             break;
  788.         if (current->signal & ~current->blocked) {
  789.             retval = -ERESTARTSYS;
  790.             break;
  791.         }
  792. #ifdef SERIAL_DEBUG_OPEN
  793.         printk("block_til_ready blocking: ttys%d, count = %d\n",
  794.                info->line, info->count);
  795. #endif
  796.         schedule();
  797.     }
  798.     current->state = TASK_RUNNING;
  799.     remove_wait_queue(&info->open_wait, &wait);
  800.     if (!tty_hung_up_p(filp))
  801.         info->count++;
  802.     info->blocked_open--;
  803. #ifdef SERIAL_DEBUG_OPEN
  804.     printk("block_til_ready after blocking: ttys%d, count = %d\n",
  805.            info->line, info->count);
  806. #endif
  807.     if (retval)
  808.         return retval;
  809.     info->flags |= ASYNC_NORMAL_ACTIVE;
  810.     return 0;
  811. }    
  812.  
  813.  
  814. /*
  815.  * This routine is called whenever a serial port is opened.
  816.  */
  817.  
  818. int rs_open( struct tty_struct *tty, struct file * filp )
  819.  
  820. {
  821.     struct async_struct    *info;
  822.     int                 retval, line;
  823.  
  824.     line = DEV_TO_SL(tty->line);
  825.     if ((line < 0) || (line >= NR_PORTS))
  826.         return( -ENODEV );
  827.     info = rs_table + line;
  828.     if (!info->base)
  829.         return( -ENODEV );
  830.  
  831. #ifdef SERIAL_DEBUG_OPEN
  832.     printk("rs_open ttyS%d, count = %d\n", info->line, info->count);
  833. #endif
  834.     info->count++;
  835.     info->tty = tty;
  836.     
  837.     tty->write       = rs_write;
  838.     tty->close       = rs_close;
  839.     tty->ioctl       = rs_ioctl;
  840.     tty->throttle    = rs_throttle;
  841.     tty->set_termios = rs_set_termios;
  842.     tty->stop        = rs_stop;
  843.     tty->start       = rs_start;
  844.     tty->hangup      = rs_hangup;
  845.  
  846.     if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
  847.         if (MAJOR(filp->f_rdev) == TTY_MAJOR)
  848.             *tty->termios = info->normal_termios;
  849.         else 
  850.             *tty->termios = info->callout_termios;
  851.     }
  852.  
  853.     /*
  854.      * Start up serial port
  855.      */
  856.     if ((retval = startup(info, 1))) return retval;
  857.  
  858.     retval = block_til_ready(tty, filp, info);
  859.     if (retval) {
  860. #ifdef SERIAL_DEBUG_OPEN
  861.         printk( "rs_open returning after block_til_ready with %d\n", retval );
  862. #endif
  863.         return retval;
  864.     }
  865.  
  866.     info->session = current->session;
  867.     info->pgrp = current->pgrp;
  868.  
  869. #ifdef SERIAL_DEBUG_OPEN
  870.     printk("rs_open ttyS%d successfull...", info->line);
  871. #endif
  872.     return 0;
  873. }
  874.  
  875.  
  876.  
  877. /*
  878.  * Boot-time initialization code: Init the serial ports present on
  879.  * this machine type.
  880.  *
  881.  * Current HW Port to minor/device name mapping:
  882.  *
  883.  *   TT                    | Falcon                    || minor | name
  884.  *  -----------------------+---------------------------++-------+-------
  885.  *   SCC B (Modem2)        | SCC B (Modem)             || 64    | ttyS0
  886.  *   SCC A (Serial2/LAN)   | SCC A (LAN)               || 65    | ttyS1
  887.  *   ST-MFP port (Modem1)  | --                        || 66    | ttyS2
  888.  *   TT-MFP port (Serial1) | ST-MFP port (no TOS name) || 67    | ttyS3
  889.  *
  890.  * The background of this mapping is that I wanted to assign the same
  891.  * minors to ports with the same capabilities. Staring with the MFPs
  892.  * would leave a hole in the first position on the Falcon!
  893.  *
  894.  * Should Serial2/LAN on the TT be split into two devices, selecting thus
  895.  * the connector used? Serial2 would be unassigned on the Falcon, and
  896.  * if one is open, opening the other would block.
  897.  * 
  898.  */
  899.  
  900. long rs_init( long kmem_start )
  901.  
  902. {    int                    i;
  903.     struct async_struct    *info;
  904.  
  905.     if (boot_info.machtype != MACH_ATARI) return( kmem_start );
  906.     
  907.     memset( &rs_event, 0, sizeof(rs_event) );
  908.     bh_base[SERIAL_BH].routine = do_softint;
  909.  
  910.     /* Initialize the async_struct's */
  911.     for( i = 0, info = rs_table; i < NR_PORTS; i++, info++ ) {
  912.         info->line           = i;
  913.         info->base             = NULL;
  914.         info->tty            = 0;
  915.         info->type           = PORT_UNKNOWN;
  916.         info->custom_divisor = 0;
  917.         info->close_delay    = 50;
  918.         info->x_char         = 0;
  919.         info->event          = 0;
  920.         info->count          = 0;
  921.         info->blocked_open   = 0;
  922.         memset(&info->callout_termios, 0, sizeof(struct termios));
  923.         memset(&info->normal_termios, 0, sizeof(struct termios));
  924.         info->open_wait      = 0;
  925.         info->xmit_wait      = 0;
  926.         info->close_wait     = 0;
  927.     }
  928.  
  929.     /* Now initialize the ports themselves */
  930.     switch( boot_info.bi_atari.model ) {
  931.  
  932.       case ATARI_TT:
  933.         atari_init_SCC(
  934.             &rs_table[0],
  935.             SCC_NORM,                        /* type */
  936.             1,                                /* Channel B */
  937.             (void *)&tt_mfp.par_dt_reg, 3, 0/* RI */
  938.         );
  939.         atari_init_SCC(
  940.             &rs_table[1],
  941.             SCC_DMA,                        /* type */
  942.             0,                                 /* Channel A */
  943.             0, 0, 0                            /* no RI */
  944.         );
  945.         atari_init_MFPser(
  946.             &rs_table[2],
  947.             MFP_CTRL,                        /* type */
  948.             0,                                /* ST-MFP */
  949.             (void *)&mfp.par_dt_reg, 6, 0    /* RI */
  950.         );
  951.         atari_init_MFPser(
  952.             &rs_table[3],
  953.             MFP_BARE,                        /* type */
  954.             1,                                /* TT_MFP */
  955.             0, 0, 0                            /* no RI */
  956.         );
  957.         break;
  958.         
  959.       case ATARI_FALCON:
  960.         atari_init_SCC(
  961.             &rs_table[0],
  962.             SCC_NORM,                        /* type */
  963.             1,                                /* Channel B */
  964.             (void *)&mfp.par_dt_reg, 6, 0    /* RI */
  965.         );
  966.         atari_init_SCC(
  967.             &rs_table[1],
  968.             SCC_NORM,                        /* type */
  969.             0,                                 /* Channel A */
  970.             0, 0, 0                            /* no RI */
  971.         );
  972.         atari_init_MFPser(
  973.             &rs_table[3],
  974.             MFP_BARE,                        /* type */
  975.             0,                                /* ST-MFP */
  976.             0, 0, 0                            /* no RI */
  977.         );
  978.         break;
  979.  
  980.     }
  981.  
  982.     return( kmem_start );
  983. }
  984.